<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .wrap {
            margin: 20px;

            .button-group {
                margin-bottom: 10px;

                & button {
                    padding: 5px 20px;
                }
            }

            .sliderBar {
                width: 1100px;
                height: 200px;
                border: 1px solid #999;
                position: relative;

                .ball {
                    width: 100px;
                    height: 100px;
                    border-radius: 50px;
                    background-color: aquamarine;
                    position: absolute;
                    left: 0px;
                    top: 0;
                }
            }
        }
    </style>
</head>

<body>
    <!-- .wrap>(.button-group>button*3)+.sliderBar>.ball -->
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="sliderBar">
            <div class="ball"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="sliderBar">
            <div class="ball"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="button-group">
            <button class="start">开始</button>
            <button class="pause">暂停</button>
            <button class="back">返回</button>
        </div>
        <div class="sliderBar">
            <div class="ball"></div>
        </div>
    </div>
</body>
<script>

    // JS运动 => 通过JS操作DOM元素,每间隔一段时间改变元素的位置  大小  透明度等

    var startList = document.querySelectorAll(".start");
    var pauseList = document.querySelectorAll(".pause");
    var backList = document.querySelectorAll(".back");
    var ballList = document.querySelectorAll(".ball");


    for (let i = 0; i < startList.length; i++) {
        let start = startList[i];
        let pause = pauseList[i];
        let back = backList[i];
        let ball = ballList[i];

        start.onclick = function () {

            animate(ball, { left: "1000px" }, function () {
                console.log("本次运动结束left:1000");
                animate(ball, { top: "100px" }, function () {
                    console.log("本次运动结束top: 500");
                    animate(ball, { opacity: "0.5" }, function () {
                        console.log("本次运动结束opacity: 0.5");
                        animate(ball, { width: "500" }, function () {
                            console.log("本次运动结束width: 500");
                        });
                    });
                });
            });

        }
        pause.onclick = function () {
            clearInterval(ball.timer);
        }

        back.onclick = function () {
            animate(ball, { left: "0", top: 0, opacity: 1, width: "100px" });
        }


    }

    // 属性提取 
    // 当前运动函数只能水平方向移动 
    // ele      运动的元素
    // params   对象参数(接收运动的属性及其终点至 cssKey end,且可以接受多个)
    // callback 每次运动完毕执行的回调函数 (把函数当成参数,传入到另一个函数中,让它在另一个函数中执行 => )


    // 问题:
    // 多元素同时运动式,启动下一个animate() 默认会暂停上一个运动的元素!!!!!!   => 最终只能跑一个

    // 解决方案:
    // 多元素同时运动时, 有几个元素就要有几个计时器  => 每个运动的元素都要有自己的计时器(而不是公用一个)

    //animate(ball, { left: "1000px", top: 600 ,opacity:0.5});
    function animate(ele, params, callback) { // params = {cssKey:end}

        // cur  1. 记录小球初始位置  2. 记录小球每次运动后的位置(以前存一个)
        // var cur = parseFloat(getStyle(ele, cssKey)); 
        // end = parseFloat(end);  // 如果有单位 => 去单位

        // debugger;
        var cur = {};  // 局部变量 => 对象,存储每一个运动的属性对应的当前值 => cur ={left:0,top:0,opacity:0}
        var end = {};  // 局部变量 => 对象,存储每一个运动的属性对应的终点值
        var speed = {}

        for (var cssKey in params) {  // 遍历传入的对象 cssKey键名 => 运动的属性名
            var curItem = parseFloat(getStyle(ele, cssKey))
            cur[cssKey] = curItem;

            var endItem = parseFloat(params[cssKey]);
            end[cssKey] = endItem;

            if (cssKey == "opacity") {  // 对于opacity来说 0-1  太小了, 一次就跑完了(没有运动效果), 而且opacity不需要带单位
                cur[cssKey] *= 1000;   // 起点值扩大1000倍
                end[cssKey] *= 1000;
            }

            speed[cssKey] = end[cssKey] > cur[cssKey] ? 20 : -20

        }
        // console.log(cur, end, speed);

        // 多元素同时运动时, 有几个元素就要有几个计时器  => 每个运动的元素都要有自己的计时器(而不是公用一个)
        // 可以尝试把计时器的编号存储到元素中  => 怎么存?

        // var obj = {};
        // obj.a = 100;  // 给对象新增属性

        // 元素节点 => html元素 也是一个特殊的对象 (官方内置属性 + 用户自定义属性)
        // ele.a = 100;   // 此属性属于用户自定义(对象中新增属性), 和官方内置属性没有关系

        // 把计时器的编号存储到元素上  => 对应元素的timer属性存储和清除计时器
        clearInterval(ele.timer);
        ele.timer = setInterval(function () {  

            var flag = true; // 假设全都到达终点
            for (var cssKey in params) {
                cur[cssKey] += speed[cssKey];

                if (cssKey == "opacity") {
                    ele.style[cssKey] = cur[cssKey] / 1000;  // 每次运动完毕缩小相应的倍数 opacity 赋值时不需要带单位  
                } else {
                    ele.style[cssKey] = cur[cssKey] + "px";
                }

                // 判断是否到达终点 => 停下了
                // 理想情况下: cur == end  刚好到达终点  (但是如果需要运动的距离(终点-起点),不是speed的倍数 => 无法满足此条件)   => 无法停止

                // 解决方案:
                // 1. cur >= end    超出end或刚好到达终点,停下了(大于最大值)  => 强制到达终点  (此方案只适用于  end > start)
                // 2. Math.abs(cur - end) < Math.abs(speed)  => 在跑一次肯定超出,没有必要跑 => 直接到达终点

                if (Math.abs(cur[cssKey] - end[cssKey]) <= Math.abs(speed[cssKey])) { // 到达终点的条件

                    // 强制到达终点  把cur的至更新为end值   !!!!!!
                    cur[cssKey] = end[cssKey];

                    if (cssKey == "opacity") {
                        ele.style[cssKey] = end[cssKey] / 1000;  // opacity 赋值时不需要带单位
                    } else {
                        ele.style[cssKey] = end[cssKey] + "px";
                    }
                } else {  // 没有到达终点
                    flag = false;  // 
                }
            }
            if (flag) {
                clearInterval(ele.timer);
                ele.timer = null;
            
                if (callback && typeof callback == "function") {  // 判断是否传入回调函数
                    callback();  // 存在就调用
                }
            }
        }, 5);
    }

    function getStyle(ele, cssKey) {
        if (window.getComputedStyle) {
            return window.getComputedStyle(ele)[cssKey];
        } else {
            return ele.currentStyle[cssKey];
        }
    }
    // console.log(getStyle(ball,"width") ); // "100px"



    // animate(ball,"left",1000,"top",600)  => animate(ball,{left:1000,top:600})
</script>

</html>